﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Castle.DynamicProxy;

namespace Common.AOP
{
    /// <summary>
    /// 日记状态枚举
    /// </summary>
    public enum LogInfoStatus
    {
        /// <summary>
        /// 开始执行
        /// </summary>
        start,
        /// <summary>
        /// 执行结束
        /// </summary>
        end,
        /// <summary>
        /// 异常
        /// </summary>
        exception
    }

    public class LogInterceptor : IInterceptor
    {
        private readonly bool _saveLog;
        private readonly ReaderWriterLockSlim _lockSlim;

        public LogInterceptor(ReaderWriterLockSlim lockSlim, bool isSaveLog = true)
        {
            _saveLog = isSaveLog;
            _lockSlim = lockSlim;
        }

        /// <summary>
        /// 拦截方法,记录日记
        /// </summary>
        /// <param name="invocation"></param>
        public void Intercept(IInvocation invocation)
        {
            var info = LogInfo(invocation, LogInfoStatus.start);
            try
            {
                Console.WriteLine("\r\n" + info);
                invocation.Proceed();
                var endInfo = LogInfo(invocation, LogInfoStatus.end);
                info += "\\r\\n" + endInfo;
                Console.Write(endInfo);
            }
            catch (Exception ex)
            {
                var tmp = "";
                info += tmp = LogInfo(invocation, LogInfoStatus.exception, ex);
                Console.WriteLine(tmp);
            }
            finally
            {
                //是否保存日记
                if (_saveLog)
                    SaveLog(info);
            }
        }

        /// <summary>
        /// 日记信息,包含方法名,方法参数,方法返回值
        /// </summary>
        /// <param name="invocation"></param>
        /// <param name="status"></param>
        /// <param name="ex"></param>
        /// <returns></returns>
        public string LogInfo(IInvocation invocation, LogInfoStatus status, Exception ex = null)
        {
            var info = "";
            if (status == LogInfoStatus.start)
            {

                info = $"{DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss")}\r\n" +
                           $"[执行方法]: {invocation.TargetType.Name}: {invocation.Method.Name}()\r\n" +
                           $"[携带参数]: {invocation.Arguments.Select(x => (x ?? "").ToString().ToList())}";
            }
            if (status == LogInfoStatus.end)
            {
                info = $"[方法返回值]: {invocation.ReturnValue}\r\n" +
                       $"[执行状态]: 执行完成\r\n";
            }
            if (status == LogInfoStatus.exception && ex != null)
            {
                info = $"{DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss")} " +
                       $"[方法执行异常]: {ex.Message} by {ex.InnerException}\r\n";
            }

            return info;
        }

        /// <summary>
        /// 保存日记
        /// </summary>
        /// <param name="logInfo"></param>
        /// <returns></returns>
        public Task SaveLog(string logInfo)
        {
            return Task.Run(() =>
             {
                 _lockSlim.EnterWriteLock();
                 var path = Directory.GetCurrentDirectory() + @"\Log\";
                 if (!Directory.Exists(path))
                 {
                     Directory.CreateDirectory(path);
                 }
                 var logName = path + $" {DateTime.Now.ToString("yyyyMMdd")}.log";
                 using (StreamWriter sw = File.AppendText(logName))
                 {
                     sw.WriteLine(logInfo);
                 };
                 _lockSlim.ExitWriteLock();
             });
        }
    }
}
